package jsr292.weaver;

import java.io.Serializable;
import java.util.List;

import jsr292.java.lang.invoke.MethodHandle;
import jsr292.java.lang.invoke.MethodType;
import jsr292.weaver.opt.OptimizerVarAllocator;
import jsr292.weaver.opt.OptimizerVarAllocator.Var;

import org.objectweb.asm.Type;

public class Debug {
  public static final boolean DEBUG = false;
  
  public static void checkAllocator(OptimizerVarAllocator allocator, MethodHandle mh) {
      List<Var> varList = allocator.getVarList();
      MethodType type = mh.type();
      
      if (type.parameterCount() != varList.size()) {
          throw new AssertionError("context vars length "+varList.size()+
                  " is different from paramater count "+type.parameterCount());
      }
      
      for(int i=0; i<varList.size(); i++) {
          Var var = varList.get(i);
          if (!isAssignableFrom(type.parameterType(i), var.getType())) {
              throw new AssertionError("variable at index "+i+" can't assign "+var.getType()+" to "+type.parameterType(i));
          }
      }
  }
  
  private static boolean isAssignableFrom(Class<?> clazz, Type type) {
      switch(type.getSort()) {
      case Type.BOOLEAN:
          return clazz == boolean.class;
      case Type.BYTE:
          return clazz == byte.class;
      case Type.SHORT:
          return clazz == short.class;
      case Type.CHAR:
          return clazz == char.class;
      case Type.INT:
          return clazz == int.class;
      case Type.LONG:
          return clazz == long.class;
      case Type.FLOAT:
          return clazz == float.class;
      case Type.DOUBLE:
          return clazz == double.class;
      case Type.ARRAY:
          if (!clazz.isArray()) {
              return clazz == Object.class || clazz == Cloneable.class || clazz == Serializable.class; 
          }
          return isAssignableFrom(clazz.getComponentType(), type.getElementType());
      case Type.OBJECT:
          Class<?> typeClass;
          try {
              typeClass = Class.forName(type.getClassName());
          } catch (ClassNotFoundException e) {
              return false;
          }
          return clazz.isAssignableFrom(typeClass);
      }
      throw new AssertionError("unknown type "+type);    
  }
}
